package org.database.manager;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;

import javax.imageio.ImageIO;

import oracle.jdbc.OracleCallableStatement;
import oracle.jdbc.OraclePreparedStatement;
import oracle.jdbc.OracleResultSet;
import oracle.ord.im.OrdImage;
import oracle.ord.im.OrdImageSignature;

import org.database.Statements;

public class ImageManager {
	private Connection conn;
	private int processedImageId;
	public static final float CLOCKWISE_90 = 90.0f;
	public static final float CLOCKWISE_180 = 180.0f;
	public static final float CLOCKWISE_270 = 270.0f;
	public static final float COUNTER_CLOCKWISE_90 = -90.0f;
	public static final float COUNTER_CLOCKWISE_180 = -180.0f;
	public static final float COUNTER_CLOCKWISE_270 = -270.0f;

	public ImageManager(Connection conn) {
		this.conn = conn;
	}

	public void saveImage(OrdImage image) {
		// String stm = "update testimage set image = ? where id = ?";
		try {
			OraclePreparedStatement pstm = (OraclePreparedStatement) conn
					.prepareStatement(Statements.UPDATE_IMAGE);
			pstm.setORAData(1, image);
			pstm.setInt(2, processedImageId);
			pstm.execute();
			pstm.close();
			conn.commit();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void saveNewImage(String filename) {
		try {
			OracleCallableStatement cstmt = (OracleCallableStatement) conn
					.prepareCall(Statements.INSERT_IMAGE);
			cstmt.registerOutParameter(1, OrdImage._SQL_TYPECODE,
					OrdImage._SQL_NAME);
			cstmt.registerOutParameter(2, OrdImageSignature._SQL_TYPECODE,
					OrdImageSignature._SQL_NAME);
			cstmt.registerOutParameter(3, Types.INTEGER);
			cstmt.execute();
			OrdImage imgProxy = (OrdImage) cstmt.getORAData(1,
					OrdImage.getORADataFactory());
			OrdImageSignature signature = (OrdImageSignature) cstmt.getORAData(
					2, OrdImageSignature.getORADataFactory());
			processedImageId = cstmt.getInt(3);
			cstmt.close();
			imgProxy.loadDataFromFile(filename);
			imgProxy.setProperties();
			signature.generateSignature(imgProxy);
			// String stm2 = "update testimage set image = ? where id = 2";
			OraclePreparedStatement pstm = (OraclePreparedStatement) conn
					.prepareStatement(Statements.UPDATE_IMAGE);
			pstm.setORAData(1, imgProxy);
			pstm.setORAData(2, signature);
			pstm.setInt(3, processedImageId);
			pstm.execute();
			pstm.close();
			conn.commit();
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public OrdImage getImageFromDB(int id) {
		PreparedStatement stm;
		OrdImage image = null;
		try {
			stm = conn.prepareStatement(Statements.SELECT_IMAGE);
			stm.setInt(1, id);
			OracleResultSet rs = (OracleResultSet) stm.executeQuery();
			while (rs.next()) {
				image = (OrdImage) rs.getORAData(1,
						OrdImage.getORADataFactory());
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		processedImageId = id;
		return image;
	}

	public void saveImageToFile(OrdImage image, String filename) {
		try {
			image.getDataInFile(filename);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void flip(OrdImage image) {
		try {
			image.process("flip");
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void contrast(OrdImage image, float percent) {
		if (percent < 0)
			throw new IllegalArgumentException("Percent must be positive value");
		try {
			image.process("contrast=" + "\"" + percent + "\"");
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void cut(OrdImage image, int x, int y) {
		try {
			image.process("cut=" + image.getWidth() + " " + image.getHeight()
					+ " " + x + " " + y);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void sharpen(OrdImage image) {
		try {
			image.process("sharpen=0 \"2.0\"");
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void rotate(OrdImage image, float angle) {
		try {
			image.process("rotate=" + "\"" + angle + "\"");
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void brightness(OrdImage image, float percent) {
		if (percent <= 0) {
			throw new IllegalArgumentException("Percent must be positive value");
		}
		try {
			image.process("gamma=\"" + percent + "\"");
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Scale image by scale ratio
	 * 
	 * @param image
	 * @param ratio
	 */
	public void scale(OrdImage image, float ratio) {
		try {
			image.process("scale=" + ratio);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void scaleWidth(OrdImage image, float ratio) {
		try {
			image.process("xScale=" + ratio);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Scale image height
	 * 
	 * @param image
	 * @param ratio
	 *            scale ratio, more than 1 scale to bigger less than 0 to
	 *            smaller
	 */
	public void scaleHeight(OrdImage image, float ratio) {
		try {
			image.process("yScale=" + ratio);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Scale image to fixed size passed in arguments
	 * 
	 * @param image
	 * @param width
	 *            width in pixels
	 * @param height
	 *            height in pixels
	 */
	public void scale(OrdImage image, int width, int height) {
		try {
			image.process("fixedScale=" + width + " " + height);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Not implemented jet
	 * 
	 * @param image
	 * @param format
	 */
	public void convertToFormat(OrdImage image, String format) {

	}

	public BufferedImage getAsBufferedImage(OrdImage image) {
		InputStream stream = null;
		BufferedImage bufferedImage = null;
		try {
			stream = image.getDataInStream();
			bufferedImage = ImageIO.read(stream);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return bufferedImage;
	}

}
